<?php

require_once 'SDOSocket.php';

/*
 * SDOVipSocket
 * 对Vip Service的socket封装
 * @author Wolfhead (Mei xueting)
 */
class SDOUserStatSocket extends SDOSocket{
    
    static public $nameMap = array(
        1 => "SndaId",
        2 => "Position",
        3 => "UserStatus",
        4 => "LoginInfo",
        5 => "NotifyMsg",
        6 => "NotifyUserMsg",
    );
    
    static protected $sequence = 0;
    static protected $serviceMap = array
    (
        'userstatservice.heartbeat'       => array("serviceId" => 14, "msgId" => 1),
        'userstatservice.queryuserstatus' => array("serviceId" => 14, "msgId" => 2),
        'userstatservice.querylogininfo'  => array("serviceId" => 14, "msgId" => 3),
        'userstatservice.dispatchnotice'  => array("serviceId" => 14, "msgId" => 4),
        'userstatservice.SendUserNotice'  => array("serviceId" => 14, "msgId" => 5),
    );
    
    static public function send($apiName,$apiParam)
    {
        $socket = new self();
        return $socket->_send($apiName,$apiParam);
    }
     
    public function pack($apiName,$apiParam)
    {
        $apiName = strtolower($apiName);
        
        $packet = '';
        $header = '';
        $packedLengthPart = '';
        $protocalTag = 0xA1;
        $headerLength = 0x00;
        $version = 0x01;
        $jump = 0xFF;
        $PacketLength = 0x00000000;
        
        $packedHeader = '';
        
        $sequence = self::$sequence++ | 0x00000000;
        $serviceId = self::$serviceMap[strtolower($apiName)]["serviceId"] | 0x00000000;
        $msgId = self::$serviceMap[strtolower($apiName)]["msgId"] | 0x00000000;
        $option = 0x00000000;
        $reserve0 = $reserve1 = $reserve2 = $reserve3 = 0x00000000;
        $sig = 0x00000000;
        
        $packedHeader .= pack("NNNNNNNNN",$serviceId,$msgId,$sequence,$option,
                $reserve0,$reserve1,$reserve2,$reserve3,$sig);
        
        $headerLength = strlen($packedHeader) + 8;
        

        
        $body = '';
        
        $body .= self::vipTLVTParams($apiParam);
        
        $PacketLenght = strlen($body) + $headerLength;
        
        $packedLengthPart .= pack("CCCCN", $protocalTag, $headerLength, $version, $jump, $PacketLenght);
        
        $packet .= $packedLengthPart . $packedHeader . $body;
        
        return $packet;
    }
    
    protected function vipTLVTParams($apiParam)
    {
        if (!is_array($apiParam))
        {
            return "";
        }
        
        $body = '';
        
        foreach ($apiParam as $key => $value)
        {
            if (is_array($value))
            {
                foreach ($value as $v)
                {
                    $body .= self::buildParam($key, $v);
                }
            }
            else
            {
                $body .= self::buildParam($key, $value);
            }
        }
        
        return $body;
    }
    
    protected function buildParam($key, $value)
    {
        static $paramMap = array(
            'SndaId' => 1,
            'Position' => 2,
            'NotifyMsg' => 5,
            'NotifyUserMsg' => 6
        );
        
        $data = '';
        
        switch ($key)
        {
            case 'SndaId':
            case 'Position':
            case 'NotifyMsg':
            case 'NotifyUserMsg':
                $alise = strlen($value) % 4;
                if ($alise != 0)
                {
                    $alise = 4 - $alise;
                    while ($alise--)
                    {
                        $value .= pack('c',0);
                    }
                }
                
                $data .= pack('nn', $paramMap[$key], strlen($value) + 4);
                $data .= $value;
                break;
            default:
                break;
        }
        
        return $data;
    }
    
    protected function headerUnpack($header)
    {
        $unpackedArray = unpack("CuTag/CuHeadLen/CuVersion/CuJump/".
                                "NuPacketLength/".
                                "NuServiceId/NuMsgId/NuSequence/NuOption/NuCode/".
                                "NuReserve0/NuReserve1/NuReserve2/NuSig",
                                  $header);

        if ($unpackedArray['uCode'] != 0)
        {
            return false;
        }
        
        return $unpackedArray;
    }

    /*
     * 得到头部长度
     * @param array $unpackedHeader
     * @return int
     */
    public function getHeaderLength()
    {
        return 0x2C;
    }
    
    /*
     * 得到数据长度
     * @param array $unpackedHeader
     * @return int
     */
    protected function getBodyLength($unpackedHeader)
    {
        return $unpackedHeader['uPacketLength'] - $unpackedHeader['uHeadLen'];
    }

    protected function unPack($param)
    {  
        $data = array();
        
        while (strlen($param))
        {
            $unpackedArray = unpack("nuNum/nuLen",
                    $param);  
            $param = substr($param, 4);
            
            
            
            switch($unpackedArray['uNum'])
            {
                case 3:
                case 4:
                    $len = $unpackedArray['uLen'] - 4 - 21;
                    $value = array();
                    $value['uid'] = trim(substr($param, 0 , 21), "\0");
                    $param = substr($param, 21);
                    $value['info'] = trim(substr($param, 0 , $len), "\0");
                    $param = substr($param, $len);
                    $data[self::$nameMap[$unpackedArray['uNum']]] = $value;
                    
                    break;
                case 5:
                case 6:
                    $len = $unpackedArray['uLen'] - 4;
                    $value = trim(substr($param, 0 , $len), "\0");
                    $param = substr($param, $len);
                    $data[self::$nameMap[$unpackedArray['uNum']]] = $value;

                    break;
                default:
                    break;    
            }
            
            $alias = 4 - ($unpackedArray['uLen'] % 4 == 0 ? 4 : $unpackedArray['uLen'] % 4);
            $param = substr($param, $alias);
        }
        
        
        return $data;
    }
}